package cn.csc.framework.common.util.date;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.date.LocalDateTimeUtil;

import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.ChronoUnit;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

/**
 * 时间工具类
 *
 * @author
 */
public class DateUtils {

    /**
     * 时区 - 默认
     */
    public static final String TIME_ZONE_DEFAULT = "GMT+8";

    /**
     * 秒转换成毫秒
     */
    public static final long SECOND_MILLIS = 1000;

    public static final String FORMAT_YEAR_MONTH_DAY_HOUR_MINUTE_SECOND = "yyyy-MM-dd HH:mm:ss";

    public static final String FORMAT_YEAR_MONTH_DAY = "yyyy-MM-dd";

    public static final String FORMAT_YEAR_MONTH_DAY_S = "yyyyMMdd";

    /**
     * 将 LocalDateTime 转换成 Date
     *
     * @param date LocalDateTime
     * @return LocalDateTime
     */
    public static Date of(LocalDateTime date) {
        // 将此日期时间与时区相结合以创建 ZonedDateTime
        ZonedDateTime zonedDateTime = date.atZone(ZoneId.systemDefault());
        // 本地时间线 LocalDateTime 到即时时间线 Instant 时间戳
        Instant instant = zonedDateTime.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return Date.from(instant);
    }

    /**
     * 将 Date 转换成 LocalDateTime
     *
     * @param date Date
     * @return LocalDateTime
     */
    public static LocalDateTime of(Date date) {
        // 转为时间戳
        Instant instant = date.toInstant();
        // UTC时间(世界协调时间,UTC + 00:00)转北京(北京,UTC + 8:00)时间
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    public static Date addTime(Duration duration) {
        return new Date(System.currentTimeMillis() + duration.toMillis());
    }

    public static boolean isExpired(Date time) {
        return System.currentTimeMillis() > time.getTime();
    }

    public static boolean isExpired(LocalDateTime time) {
        LocalDateTime now = LocalDateTime.now();
        return now.isAfter(time);
    }

    public static long diff(Date endTime, Date startTime) {
        return endTime.getTime() - startTime.getTime();
    }

    /**
     * 创建指定时间
     *
     * @param year  年
     * @param month 月
     * @param day   日
     * @return 指定时间
     */
    public static Date buildTime(int year, int month, int day) {
        return buildTime(year, month, day, 0, 0, 0);
    }

    public static LocalDateTime buildLocalDateTime(int year, int month, int day) {
        return LocalDateTime.of(year, month, day, 0, 0, 0);
    }

    /**
     * 创建指定时间数组
     *
     * @param year0   年
     * @param month0  月
     * @param day0    日
     * @param year1   年
     * @param month1  月
     * @param day1    日
     * @return 指定时间
     */
    public static LocalDateTime[] buildBetweenTime(int year0, int month0, int day0, int year1, int month1, int day1){
        LocalDateTime[] arr = new LocalDateTime[2];
        arr[0] = buildLocalDateTime(year0,month0,day0);
        arr[1] = buildLocalDateTime(year1,month1,day1);
        return arr;
    }

    /**
     * 创建指定时间
     *
     * @param year   年
     * @param month  月
     * @param day    日
     * @param hour   小时
     * @param minute 分钟
     * @param second 秒
     * @return 指定时间
     */
    public static Date buildTime(int year, int month, int day,
                                 int hour, int minute, int second) {
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year);
        calendar.set(Calendar.MONTH, month - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day);
        calendar.set(Calendar.HOUR_OF_DAY, hour);
        calendar.set(Calendar.MINUTE, minute);
        calendar.set(Calendar.SECOND, second);
        calendar.set(Calendar.MILLISECOND, 0); // 一般情况下，都是 0 毫秒
        return calendar.getTime();
    }

    /**
     * 创建指定时间数组
     *
     * @param year0   年
     * @param month0  月
     * @param day0    日
     * @param year1   年
     * @param month1  月
     * @param day1    日
     * @return 指定时间
     */
    public static Date[] buildBetweenDateTime(int year0, int month0, int day0, int year1, int month1, int day1){
        Date[] arr = new Date[2];
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR, year0);
        calendar.set(Calendar.MONTH, month0 - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day0);
        arr[0] = calendar.getTime();

        calendar.set(Calendar.YEAR, year1);
        calendar.set(Calendar.MONTH, month1 - 1);
        calendar.set(Calendar.DAY_OF_MONTH, day1);
        arr[1] = calendar.getTime();
        return arr;
    }


    public static Date max(Date a, Date b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return a.compareTo(b) > 0 ? a : b;
    }

    public static LocalDateTime max(LocalDateTime a, LocalDateTime b) {
        if (a == null) {
            return b;
        }
        if (b == null) {
            return a;
        }
        return a.isAfter(b) ? a : b;
    }

    public static boolean beforeNow(Date date) {
        return date.getTime() < System.currentTimeMillis();
    }

    public static boolean afterNow(Date date) {
        return date.getTime() >= System.currentTimeMillis();
    }

    public static boolean afterNow(LocalDateTime localDateTime) {
        return localDateTime.isAfter(LocalDateTime.now());
    }

    /**
     * 比较日期为当前日志之后
     * @param localDate
     * @return
     */
    public static boolean afterNow(LocalDate localDate) {
        return localDate.isAfter(LocalDate.now());
    }

    /**
     * 比较日期为当前日期或者之后
     * @param localDate 比较日期
     * @return
     */
    public static boolean afterEqualNow(LocalDate localDate) {
        return localDate.isAfter(LocalDate.now()) || localDate.isEqual(LocalDate.now());
    }

    /**
     * 比较日期为当前日期之前
     * @param localDate
     * @return
     */
    public static boolean beforeNow(LocalDate localDate) {
        return localDate.isBefore(LocalDate.now());
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param field  日历字段.<br/>eg:Calendar.MONTH,Calendar.DAY_OF_MONTH,<br/>Calendar.HOUR_OF_DAY等.
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(int field, int amount) {
        return addDate(null, field, amount);
    }

    /**
     * 计算当期时间相差的日期
     *
     * @param date   设置时间
     * @param field  日历字段 例如说，{@link Calendar#DAY_OF_MONTH} 等
     * @param amount 相差的数值
     * @return 计算后的日志
     */
    public static Date addDate(Date date, int field, int amount) {
        if (amount == 0) {
            return date;
        }
        Calendar c = Calendar.getInstance();
        if (date != null) {
            c.setTime(date);
        }
        c.add(field, amount);
        return c.getTime();
    }

    /**
     * 计算与输入日期相差的日期
     * @param date 日期
     * @param amount 相差的数值
     * @param unit 单位。<br/>eg:ChronoUnit.DAYS,<br/>ChronoUnit.WEEKS等.
     * @return
     */
    public static LocalDate datePlus(LocalDate date, Long amount, ChronoUnit unit) {
        if (amount == 0) {
            return date;
        }
        return date.plus(amount, unit);
    }

    /**
     * 日期天数增减
     * @param date 日期
     * @param amount 天数
     * @return
     */
    public static LocalDate dateDayPlus(LocalDate date, Long amount) {
        return datePlus(date, amount, ChronoUnit.DAYS);
    }

    /**
     * 当前日期天数增减
     * @param amount 天数
     * @return
     */
    public static LocalDate dateDayPlus(Long amount) {
        return datePlus(LocalDate.now(), amount, ChronoUnit.DAYS);
    }


    /**
     * 获取当前日期的字符串
     * @param dfStr 日期格式字符串
     * @return
     */
    public static String getCurrentDate(String dfStr){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(dfStr);
        return LocalDate.now().format(df);
    }

    /**
     * 获取当前日期的字符串,默认格式为yyyyMMdd
     * @return
     */
    public static String getCurrentDate(){
        return getCurrentDate(FORMAT_YEAR_MONTH_DAY_S);
    }

    /**
     * 是否今天
     *
     * @param date 日期
     * @return 是否
     */
    public static boolean isToday(Date date) {
        if (date == null) {
            return false;
        }
        return DateUtil.isSameDay(date, new Date());
    }

    /**
     * 是否今天
     *
     * @param date 日期
     * @return 是否
     */
    public static boolean isToday(LocalDateTime date) {
        return LocalDateTimeUtil.isSameDay(date, LocalDateTime.now());
    }


    /**
     * 日期转换为String
     * @param date
     * @param dfStr 日期格式字符串
     * @return
     */
    public static String date2Str(LocalDate date, String dfStr){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(dfStr);
        return date.format(df);
    }

    /**
     * 当前日期转换为String
     * @param dfStr 日期格式字符串
     * @return
     */
    public static String date2Str(String dfStr){
        return date2Str(LocalDate.now(), dfStr);
    }

    /**
     * 字符串转换为LocalDate
     * @param dateStr 日期字符串
     * @param dfStr 日期格式字符串
     * @return
     */
    public static LocalDate str2Date(String dateStr, String dfStr){
        DateTimeFormatter formatter = DateTimeFormatter.ofPattern(dfStr);
        return LocalDate.parse(dateStr, formatter);
    }

    /**
     * 字符串转换为LocalDate, 默认格式为yyyyMMdd
     * @param dateStr 日期字符串
     * @return
     */
    public static LocalDate str2Date(String dateStr){
        return str2Date(dateStr, FORMAT_YEAR_MONTH_DAY_S);
    }


    /**
     * 构建查询工作日的参数字符串
     * @param start 开始日期
     * @param count 日期个数
     * @return
     */
    public static String getWorkdayParams(LocalDate start, Integer count){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY);
        return IntStream.range(0,count).mapToObj(n-> df.format(start.plusDays(n))).collect(Collectors.joining(","));
    }

    /**
     * 构建查询工作日的参数字符串, 开始日期为当前日期下一天，12个日期字符串
     * @return
     */
    public static String getWorkdayParams(){
        return getWorkdayParams(LocalDate.now().plusDays(1),12);
    }

    /**
     * 构建查询工作日的参数字符串列表
     * @param start 开始日期
     * @param count 日期个数
     * @return
     */
    public static List<String> getWorkdayParamsList(LocalDate start, Integer count){
        DateTimeFormatter df = DateTimeFormatter.ofPattern(FORMAT_YEAR_MONTH_DAY);
        return IntStream.range(0,count).mapToObj(n-> df.format(start.plusDays(n))).collect(Collectors.toList());
    }

    /**
     * 构建查询工作日的参数字符串列表, 开始日期为当前日期的下一天，12个日期字符串
     * @return
     */
    public static List<String> getWorkdayParamsList(){
        return getWorkdayParamsList(LocalDate.now().plusDays(1),12);
    }


}
